/*+***********************************************************************************
 Filename: 03_tinycore_step02\src\core.v
 Description: demo the construction of a simple tiny-core.
              step02: a core can execute ADI and JAL.

 Modification:
   2022.10.13 Creation   H.Zheng

Copyright (C) 2022  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

Thanks: some codes are learned from Bob Hu's E203 Humingbird project source. His
        Copyright announcement see the bottom of this file.

***********************************************************************************-*/



module core (
    input wire core_clk,
    input wire reset_n,
    output wire [31:0] ibus_addr,
    output wire ibus_re,  //read enable
    input wire [31:0] instruction,
    output wire [31:0] monitor_port
);

    //PC
    reg [31:0] program_counter;
    wire [31:0] pc_next;

//    always @(posedge core_clk or negedge reset_n) begin
    always @(posedge core_clk) begin
        if (~reset_n) begin
            program_counter <= ~(32'b0);
        end
        else begin
            program_counter <= pc_next;
        end
    end

    assign ibus_addr = program_counter>>2;
    assign ibus_re = 1'b1;

    //
    //decoder
    //ADI and J only.

    wire [6:0] opcode = instruction[6:0];
    wire [2:0] funct3 = instruction[14:12];

    wire opcode_OP_IMM = (opcode == 7'b0010011);
    wire opcode_OP_JAL = (opcode == 7'b1101111);

    wire [4:0] i_rd_idx = instruction[11:7];
    wire [4:0] i_rs1_idx = instruction[19:15];
    wire [31:0] i_imm_J = {{12{instruction[31]}},instruction[19:12],instruction[20],instruction[30:21],1'b0};
    wire [31:0] i_imm_I = {{21{instruction[31]}},instruction[30:20]};

    wire inst_ADI = opcode_OP_IMM & (funct3 == 3'b000);
    wire inst_JAL = opcode_OP_JAL;
    wire inst_J = inst_JAL & (i_rd_idx == 5'b0);

    wire [4:0] i_rs2_idx = instruction[24:20]; //not use now

    //execution of ADI
    //

    //fetch rs1 value from Register File
    wire[31:0] rf_rs1data;
    wire[31:0] rf_rs2data;
    wire rf_rdwen;
    wire[31:0] rf_rd_data;
    wire[31:0] x16_value;
    
    //register file module
    regfile m_regfile(
      .reset_n(reset_n),
      .i_rf_rs1idx(i_rs1_idx),
      .i_rf_rs2idx(i_rs2_idx),
      .rf_rs1data(rf_rs1data),
      .rf_rs2data(rf_rs2data),
      .i_rf_rdidx(i_rd_idx),
      .i_rf_rdwen(rf_rdwen),
      .i_rf_rd_data(rf_rd_data),
      .i_rf_rd_wr_clk(~core_clk),
      .x16_value(x16_value)
    );

    //ADI operation
    wire [31:0] adi_result = rf_rs1data + i_imm_I;

    //write back
    assign rf_rd_data = adi_result;
    assign rf_rdwen = inst_ADI;

    //Jump
    //
    assign pc_next = inst_JAL ? program_counter + i_imm_J : program_counter + 4;  




    //
    assign monitor_port = x16_value;
    //assign monitor_port = {inst_J, inst_ADI, ibus_addr[3:0]};
//    assign monitor_port = {rf_rdwen, rf_rdidx};
//    assign monitor_port = {rf_rdwen, i_imm_I[4:0]};



endmodule

